#include <ucontext.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <uuid/uuid.h>
#include <unistd.h>
#include <setjmp.h>
#include <sys/syscall.h>   /* For SYS_xxx definitions */

#if 0

#include "sysy_lib.h"
#include "buffer.h"

typedef void (*callback_t)(void *);

static void __callback(void *arg)
{
        int ret;
        task_t *task = arg;

        int rand = _random() % 3;

        sleep(rand);

        task->retval = _random();
        DINFO("sleep %u, retval %u\n", rand, task->retval);

        ret = schedule_reply(task->schedule, task->id, task->retval, NULL);
        if(ret)
                UNIMPLEMENTED(__DUMP__);
}

typedef struct {
        callback_t callback;
        void *arg;
} arg_t;

static void *__exec(void *_arg)
{
        arg_t *arg = _arg;

        arg->callback(arg->arg);

        yfree((void **)&_arg);

        return NULL;
}

static int __async_op(callback_t callback, void *_arg)
{
        int ret;
        pthread_t th;
        pthread_attr_t ta;
        arg_t *arg;

        (void) pthread_attr_init(&ta);
        (void) pthread_attr_setdetachstate(&ta,PTHREAD_CREATE_DETACHED);

        ret = ymalloc((void **)&arg, sizeof(*arg));
        if (unlikely(ret))
                GOTO(err_ret, ret);

        arg->arg = _arg;
        arg->callback = callback;

        ret = pthread_create(&th, &ta, __exec, arg);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}

#if 0

static int __task1__ = 1;
static int __task2__ = 1;

void func1(void * arg)  
{
        int ret;
        task_t *task = arg;

        DINFO("test1_1, retval %u\n", task->retval);

        ret = __async_op(__callback, arg);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield(); 

        DINFO("test1_2, retval %u\n", task->retval);

        ret = __async_op(__callback, arg);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield();

        DINFO("test1_3, retval %u\n", task->retval);

        ret = __async_op(__callback, arg);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield();

        DINFO("test1_4, retval %u\n", task->retval);
        DINFO("test1 finished\n");

        __task1__ = 0;
}

void func2(void *arg)  
{
        int ret;
        task_t *task = arg;

        DINFO("test2_1, retval %u\n", task->retval);

        ret = __async_op(__callback, arg);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield();

        DINFO("test2_2, retval %u\n", task->retval);

        ret = __async_op(__callback, arg);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield(); 

        DINFO("test1_3, retval %u\n", task->retval);

        ret = __async_op(__callback, arg);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield(); 

        DINFO("test1_4, retval %u\n", task->retval);
        DINFO("test2 finished\n");

        __task2__ = 0;
}

int schedule_test()
{
        int ret;
        task_t task1, task2;

        ret = schedule_init(NULL);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        (void) task2;
        (void) task1;

#if 1
        ret = schedule_create(&task1, "task1");
        if (unlikely(ret))
                GOTO(err_ret, ret);

        schedule_run_task(&task1, func1, &task1);
#endif

#if 1
        ret = schedule_create(&task2, "task2");
        if (unlikely(ret))
                GOTO(err_ret, ret);

        schedule_run_task(&task2, func2, &task2);
#endif

        while (__task1__ || __task2__) {
                ret = schedule_poll(10);
                if (unlikely(ret)) {
                        if (ret == ETIMEDOUT)
                                continue;
                        else
                                GOTO(err_ret, ret);
                }

                DINFO("weak up\n");

                schedule_run();
        }
#if 0
        while(!schedule_finished()){
                task_resume(&task1);
                task_resume(&task2);
        }
#endif

        DINFO("finish\n");

        return 0;
err_ret:
        return ret;
}

int main()  
{
        schedule_test();

        return 0;
}

#else

static void __test_msg_exec(void *_buf)
{
        int ret;
        buffer_t *buf = _buf;
        char str[MAX_NAME_LEN];
        task_t task;

        DINFO("init task %s %p, stage0\n", str, buf);

        mbuffer_get(buf, str, buf->len);

        mbuffer_free(buf);
        yfree((void **)&buf);

        task = schedule_get_task();
        ret = __async_op(__callback, &task);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield();

        DINFO("task %s, stage1, retval %u\n", str, task.retval);

        ret = __async_op(__callback, &task);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield();

        DINFO("task %s, stage2, retval %u\n", str, task.retval);

        ret = __async_op(__callback, &task);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        schedule_yield();

        DINFO("task %s, stage3, retval %u\n", str, task.retval);
        DINFO("task %s finished\n", str);
}

static  int __test_request(schedule_t *schedule, int seq)
{
        int ret, retry = 0;
        buffer_t *buf;
        char str[MAX_NAME_LEN];

        snprintf(str, MAX_NAME_LEN, "task%u", seq);

        ret = ymalloc((void **)&buf, sizeof(*buf));
        if (unlikely(ret))
                GOTO(err_ret, ret);

        DINFO("task %u %p\n", seq, buf);

        mbuffer_init(buf, 0);
        mbuffer_appendmem(buf, str, strlen(str) + 1);

        //YASSERT(buf->len > 1);

        DINFO("new request %s\n", str);

retry:
        ret = schedule_request(schedule, -1, __test_msg_exec, buf);
        if (unlikely(ret)) {
                if (ret == ENOSPC) {
                        DWARN("schedule full, retry %u\n", retry);
                        sleep(1);
                        retry++;
                        goto retry;
                } else
                        GOTO(err_ret, ret);
        }

        return 0;
err_ret:
        return ret;
}

static void *__test_request_worker(void *args)
{
        int i;
        schedule_t *schedule = args;

        for (i = 0; i < TEST_MAX; i++) {
                __test_request(schedule, i);
        }

        return NULL;
}

static int __test_request_create(schedule_t *schedule)
{
        int ret;
        pthread_t th;
        pthread_attr_t ta;

        (void) pthread_attr_init(&ta);
        (void) pthread_attr_setdetachstate(&ta,PTHREAD_CREATE_DETACHED);

        ret = pthread_create(&th, &ta, __test_request_worker, schedule);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}

int main()  
{
        int ret;
        schedule_t *schedule;

        ret = schedule_init(&schedule);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = __test_request_create(schedule);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        while (1) {
                ret = schedule_poll(10);
                if (unlikely(ret)) {
                        if (ret == ETIMEDOUT)
                                continue;
                        else
                                GOTO(err_ret, ret);
                }

                DINFO("weak up\n");

                schedule_run();
        }
  
        return 0;
err_ret:
        return ret;
}  

#endif
#endif

int main ()
{
        return 0;
}
